package com.example.downloader.upload2;

import android.os.AsyncTask;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Task<R> implements UploadProgress {
    private int mProgress;
    static final int WAITING = 0;
    static final int COMPRESS = 1;
    static final int UPLOAD = 2;
    static final int FINISHED = 3;
    static final int ERROR = -1;
    static final int CANCEL = -2;
    private final List<Callback> mCallbacks = new ArrayList();
    private int mStatus = WAITING;
    private final TaskExecutor<R> mLoader;
    private R mResult;
    private WorkTask mTask;
    private TaskQueue<R> mTaskQueue;
    private final String mPath;

    public Task(TaskExecutor<R> loader, TaskQueue<R> taskQueue, String path) {
        mLoader = loader;
        mTaskQueue = taskQueue;
        mPath = path;
    }

    void execute() {
        if (mTask == null) {
            mTask = new WorkTask();
            mTask.execute(mPath);
        }
    }

    void finish() {
        Iterator<Callback> iterator = mCallbacks.iterator();
        while (iterator.hasNext()) {
            final Callback callback = iterator.next();
            iterator.remove();
//            mTaskQueue.releaseCallback();
        }

    }

    void cancel() {
        if (mTask != null) {
            mTask.cancel(true);
            mTask = null;
        }
    }


    void addCallback(Callback<R> callback) {
        mCallbacks.add(callback);
    }

    void removeCallback(Callback<R> callback) {
        mCallbacks.remove(callback);
    }

    boolean pushCallback(Callback<R> callback) {
        if (!isActive())
            return false;
        switch (mStatus) {
            case WAITING:
                callback.onWaiting();
                break;
            case COMPRESS:
                callback.onCompressing();
                break;
            case UPLOAD:
                callback.onUploading(mProgress);
                break;
            case FINISHED:
                callback.onFinished(mResult);
                break;
            case ERROR:
                callback.onError();
                break;
            case CANCEL:
                callback.onCancel();
                break;
        }
        addCallback(callback);
        return true;
    }


    @Override
    public void setUploadProgress(int progress) {
        if (mTask != null) {
            mTask.setUploadProgress(progress);
        }
    }

    boolean isActive() {
        return mTask != null || mTask.getStatus() != AsyncTask.Status.FINISHED;
    }

    private class WorkTask extends AsyncTask<String, Integer, R> {
        @Override
        protected void onPostExecute(R t) {
            if (mStatus != ERROR) {
                mStatus = FINISHED;
                mResult = t;
                for (Callback callback : mCallbacks) {
                    callback.onFinished(t);
                }
            }

        }

        @Override
        protected void onCancelled(R r) {
            super.onCancelled(r);
            mStatus = CANCEL;
            for (Callback callback : mCallbacks) {
                callback.onCancel();
            }
        }


        @Override
        protected void onPreExecute() {
            mStatus = WAITING;
            for (Callback<R> callback : mCallbacks) {
                callback.onWaiting();
            }
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            switch (values[0]) {
                case COMPRESS:
                    mStatus = COMPRESS;
                    for (Callback callback : mCallbacks) {
                        callback.onCompressing();
                    }

                    break;
                case UPLOAD:
                    mStatus = UPLOAD;
                    mProgress = values[1];
                    for (Callback callback : mCallbacks) {
                        callback.onUploading(mProgress);
                    }
                    break;
                case ERROR:
                    for (Callback callback : mCallbacks) {
                        callback.onError();
                    }
                    break;

            }

        }

        @Override
        protected R doInBackground(String... strings) {
            final String filePath = strings[0];
            try {
                publishProgress(COMPRESS);
                final String compressingPath = mLoader.onCompressing(filePath);
                return mLoader.onUploading(compressingPath, Task.this);
            } catch (Throwable throwable) {
                throwable.printStackTrace();
                publishProgress(ERROR);

            }


            return null;
        }

        public void setUploadProgress(int progress) {
            publishProgress(UPLOAD, progress);
        }
    }
}
